#include <helpers\game\game.h>

namespace DelGE
{
	namespace Helpers
	{
		namespace Game
		{
			Game::Game()
			{
				this->pGameWindow = NULL;
				this->bIsFullscreen = false;
				this->bHideMouse = false;
				this->bIsRunning = false;
				this->pEngine = new Engine();
			}

			Game::~Game()
			{
				this->pGameWindow = NULL;
				if (pEngine != NULL)
				{
					delete this->pEngine; this->pEngine = NULL;
				}
			}

			void Game::CreateGraphicsWindow(string sTitle, int iWidth, int iHeight, int iBitDepth, bool bFullscreen)
			{
				if (this->pGameWindow == NULL)
				{
					this->oDesktopMode = this->pEngine->GetSystem()->GetCurrentVideoMode();

					if (bFullscreen == false)
					{
						this->pGameWindow = this->pEngine->GetSystem()->CreateWindow(sTitle, iWidth, iHeight, DelGESystemWindowStyle_FixedSize);
						this->bIsFullscreen = false;
					}
					else
					{
						this->pGameWindow = this->pEngine->GetSystem()->CreateWindow(sTitle, iWidth, iHeight, DelGESystemWindowStyle_Frameless);

						SystemVideoMode videoMode = this->pEngine->GetSystem()->FindNearestSupportedVideoMode(SystemVideoMode(iWidth, iHeight, iBitDepth));
						this->pEngine->GetSystem()->ChangeVideoMode(videoMode);

						this->bIsFullscreen = true;
					}

					this->pContext = this->pEngine->GetGraphics()->CreateContext(this->pGameWindow);
					this->pEngine->GetGraphics()->SetCurrentContext(this->pContext);

					this->pEngine->GetGraphics()->Setup2DProjection();

					this->iBitDepth = iBitDepth;

					this->pEngine->SetWindowHandle(this->pGameWindow);
				}
			}
			
			void Game::DestroyGraphicsWindow()
			{
				if (this->pGameWindow != NULL)
					this->pEngine->GetSystem()->DestroyGadget(this->pGameWindow);

				if (this->bIsFullscreen)
					this->pEngine->GetSystem()->RestoreVideoMode();

				this->pGameWindow = NULL;
			}

			void Game::ToggleFullscreen()
			{
				if (this->bIsFullscreen)
					this->SwitchToWindowed();
				else
					this->SwitchToFullscreen();
			}

			void Game::SwitchToFullscreen()
			{
				// Go fullscreen
				this->bIsFullscreen = true;

				// Change the video mode
				SystemVideoMode videoMode = 
				this->pEngine->GetSystem()->FindNearestSupportedVideoMode(SystemVideoMode(this->GetGraphicsWidth(), 
																						  this->GetGraphicsHeight(), 
																						  this->GetGraphicsBitDepth()));
				this->pEngine->GetSystem()->ChangeVideoMode(videoMode);

				// Change the window
				this->pGameWindow->SetStyle(DelGESystemWindowStyle_Frameless);
				this->pGameWindow->SetFocus();
				this->pGameWindow->SetPosition(0, 0);
			}

			void Game::SwitchToWindowed()
			{
				// Go windowed
				this->bIsFullscreen = false;

				// Change the video mode
				this->pEngine->GetSystem()->RestoreVideoMode();

				// Change the window
				this->pGameWindow->SetStyle(DelGESystemWindowStyle_FixedSize);
				this->pGameWindow->SetFocus();
				this->pGameWindow->SetPosition(0, 0);
			}

			void Game::HideMouse()
			{
				this->bHideMouse = true;
			}

			void Game::ShowMouse()
			{
				this->bHideMouse = false;
			}

			int Game::GetGraphicsWidth()
			{
				return this->pGameWindow->GetWidth();
			}

			int Game::GetGraphicsHeight()
			{
				return this->pGameWindow->GetHeight();
			}

			int Game::GetGraphicsBitDepth()
			{
				return this->iBitDepth;
			}

			void Game::AddScreen(int iScreenIndex, Screen *pScreen)
			{
				if (!this->mScreenMap[iScreenIndex])
					this->mScreenMap[iScreenIndex] = pScreen;
			}

			void Game::RemoveScreen(int iScreenIndex)
			{
				map<int, Screen*>::iterator itor;

				itor = this->mScreenMap.find(iScreenIndex);
				if (itor != this->mScreenMap.end())
					this->mScreenMap.erase(itor);
			}

			void Game::RenderCurrentScreen()
			{
				this->pCurrentScreen->Render();		
			}

			void Game::UpdateCurrentScreen(float fDelta)
			{
				this->pCurrentScreen->Update(fDelta);
			}

			Engine* Game::GetEngine()
			{
				return this->pEngine;
			}

			void Game::Run(int iScreenIndex)
			{
				SystemTimer* pTimer;
				float fDelta;

				this->pCurrentScreen = this->mScreenMap[iScreenIndex];

				if (this->pCurrentScreen)
				{
					this->pEngine->CreateDefaultModules();
					this->pEngine->GetGraphics()->SetBlendMode(DelGEGraphicsBlendMode_Alpha);
					this->pEngine->GetGraphics()->Begin2DRendering();
					this->Startup();

					pTimer = this->pEngine->GetSystem()->CreateTimer();

					this->bIsRunning = this->bHasFocus = true;
					fDelta = 0;

					this->pCurrentScreen->SetEngine(this->pEngine);
					this->pCurrentScreen->Load();

					while (this->bIsRunning)
					{
						pTimer->Start();

						this->pEngine->Update();

						DelGEEvent sEvent;
						while (EventManager::PopEvent(sEvent))
						{
							switch (sEvent.eType)
							{
							case DelGE_Event_SystemWindow_Close:
								bIsRunning = false;
								break;

							case DelGE_Event_SystemWindow_LostFocus:
								this->bHasFocus = false;
								break;

							case DelGE_Event_SystemWindow_GainedFocus:
								this->bHasFocus = true;
								break;

							case DelGE_Event_SystemWindow_MouseLeave:
								if (this->bHideMouse == true)
									this->pEngine->GetSystem()->ShowMouse();
								break;

							case DelGE_Event_SystemWindow_MouseEnter:
								if (this->bHideMouse == true)
									this->pEngine->GetSystem()->HideMouse();
								break;

							case DelGE_Event_SystemWindow_CharacterInput:
								this->pEngine->PushChar(sEvent.CharacterInputData.cCharacterInput);
								break;

							case DelGE_Event_Game_Quit:
								this->bIsRunning = false;
								break;

							case DelGE_Event_Game_ChangeScreen:
								{
									int iScreenIndex = sEvent.ScreenData.iScreenIndex;

									if (this->mScreenMap.find(iScreenIndex) != this->mScreenMap.end())
									{
										this->pCurrentScreen->Unload();
										this->pCurrentScreen = this->mScreenMap[iScreenIndex];
										this->pCurrentScreen->SetEngine(this->pEngine);
										this->pCurrentScreen->Load();
									}
									break;
								}

							case DelGE_Event_Game_SwitchToFullscreen:
								this->SwitchToFullscreen();
								break;

							case DelGE_Event_Game_SwitchToWindowed:
								this->SwitchToWindowed();
								break;

							case DelGE_Event_Game_ToggleFullscreen:
								this->ToggleFullscreen();
								break;
							}
						}

						
						this->Render();

						pTimer->Stop();

						fDelta = pTimer->GetDeltaTime() / 1000.0f;

						this->Update(fDelta);
					}

					this->pCurrentScreen->Unload();

					this->pEngine->GetSystem()->DestroyTimer(pTimer);

					this->Shutdown();
					this->pEngine->DestroyDefaultModules();
				}
			}
		}
	}
}